#ifndef RT_VIDEO_H__
#define RT_VIDEO_H__

#include <rtthread.h>
#include <stdint.h>

#include "videodef.h"

#define VIDIOC_SET_XCLK    0x5680
#define VIDIOC_PWDN        0x5681
#define VIDIOC_RESET       0x5682


#ifndef VIDEO_FRAME_MAX
#define VIDEO_FRAME_MAX 8
#endif

struct camif_ops;
struct camif_buf;
struct video_device;

struct rt_camif_device
{
    struct rt_device parent;
    const struct camif_ops *ops;

    uint8_t slv_addr;
    struct camif_buf *active;
};
typedef struct rt_camif_device rt_camif_t;

struct camif_buf
{
    rt_list_t node;
    uint16_t index;
    int16_t status;
    void *data;
    uint32_t bufsz;
    void (*complete)(struct camif_buf *buf, int status);
    struct video_device *vid;
};

struct camif_ops
{
    int (*init)(rt_camif_t *ci);
    void (*deinit)(rt_camif_t *ci);
    int (*sccb_read)(rt_camif_t *ci, uint8_t slv, uint16_t reg, int reglen, uint8_t *data);
    int (*sccb_write)(rt_camif_t *ci, uint8_t slv, uint16_t reg, int reglen, uint8_t *data);
    int (*stream_start)(rt_camif_t *ci);
    int (*stream_stop)(rt_camif_t *ci);
    int (*buf_active)(rt_camif_t *ci, struct camif_buf *buf);
    void (*pwdn)(rt_camif_t *ci, int level);
    void (*reset)(rt_camif_t *ci, int level);
    int (*ioctl)(rt_camif_t *ci, int cmd, long args);
    int (*set_format)(rt_camif_t *ci, struct video_format *fmt);
};

struct camctl_ops;

struct vbuf_item
{
    rt_list_t node;
    struct video_buffer *vb;
};

struct vbuf_container
{
    uint16_t memtype;
    uint16_t count;
    struct camif_buf *alloced[VIDEO_FRAME_MAX];
    rt_list_t in_que;
    rt_list_t out_que;
};

struct video_device
{
    struct rt_device parent;

    /* init these in camera driver */
    const struct video_ops *ops;
    rt_camif_t *ci;
    /**/
    uint32_t chipid;

    struct vbuf_container vbufs;
    rt_wqueue_t wq_in;
};
typedef struct video_device rt_video_t;

struct video_ops
{
    int (*init)(rt_video_t *vid);
    void (*deinit)(rt_video_t *vid);
    int (*set_format)(rt_video_t *vid, struct video_format *fmt);
    int (*get_format)(rt_video_t *vid, struct video_format *fmt);
    int (*stream_enable)(rt_video_t *vid, int en);
};

rt_camif_t* rt_camif_get(const char *name);
int rt_camif_reg_write(rt_camif_t *ci, uint8_t slv, uint16_t reg, uint8_t *data);
int rt_camif_reg_read(rt_camif_t *ci, uint8_t slv, uint16_t reg, uint8_t *data);
int rt_camif_register(rt_camif_t *ci, const char *name, void *userdata);
void rt_camif_complete(rt_camif_t *ci, int status);
int rt_camif_power_reset(rt_camif_t *ci, int pwdn_lv, int reset_lv);

int rt_video_register(rt_video_t *vid, const char *name, void *userdata);

#endif
